package com.code.google.wormon.base;

/**
 * The Engine of a Game, this class is responsible to process a keep running a
 * game instance.
 * 
 * @author volnei
 * 
 */
public class Engine implements Runnable {
	/**
	 * Default refresh rate value.
	 */
	public static final Long DEFAULT_REFRESH_RATE = 10l;

	/**
	 * The running flag.
	 */
	private Boolean running = Boolean.FALSE;

	/**
	 * The game refresh rate.
	 */
	private Long refreshRate = DEFAULT_REFRESH_RATE;

	/**
	 * The game instance
	 */
	private Game game;

	/**
	 * 
	 * @param game
	 */
	public Engine(Game game) {
		super();
		this.game = game;
	}

	/**
	 * Sets the running flag to true and execute game
	 */
	@Override
	public void run() {
		try {
			Long startTime = 0l;
			Long endTime = 0l;
			Long ellapsedTime = 0l;
			Long exceddedTime = 0l;
			game.start();
			running = true;
			while (isRunning()) {
				startTime = System.currentTimeMillis();
				game.doLogics();
				game.doGraphics();
				endTime = System.currentTimeMillis();
				ellapsedTime = endTime - startTime;
				if (ellapsedTime < refreshRate) {
					sleep(refreshRate - ellapsedTime);
				} else {
					exceddedTime += ellapsedTime - refreshRate;
					while (exceddedTime > refreshRate) {
						game.doLogics();
						exceddedTime -= refreshRate;
					}
				}
			}
		} finally {
			game.stop();
		}
	}

	/**
	 * Sleeps the game for specified time
	 * 
	 * @param time
	 *            the time to sleep
	 */
	private void sleep(Long time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			// do nonhing
		}
	}

	public void start() {
		Thread engineThread = new Thread(this);
		engineThread.start();
	}

	public Boolean isRunning() {
		return running;
	}

	public Long getRefreshRate() {
		return refreshRate;
	}

	public void setRefreshRate(Long refreshRate) {
		this.refreshRate = refreshRate;
	}

	public Game getGame() {
		return game;
	}

	public void setGame(Game game) {
		this.game = game;
	}
}
